class RPGCamera
{
//eMotion Camera
public:
	user				Usr;	//Active Player
	ICameraSceneNode	Nde;	//Camera Node
	vector3df		 	Epd;	//Camera Ellipsoid
	stringw				Ste;	//Camera State
	line3df				Spl[];	//Spline Path Array
	vector3df			DltRot;	//Delta Rotation
	vector3df			DltPos;	//Delta Position
	vector3df			DltOfs;	//Delta Target Offset
	ITimer				Tmr;	//Local RPGCamera Timer
	
	RPGCamera( vector3df, ISceneNode, stringw, int, line3df[] );
	Update()
	{
		//Calculate Camera Position From Delta Position
		vector3df	UsrPos		= Usr.Nde.getPosition();	//User Position
		vector3df	CamPos		= Nde.getPosition();		//Camera Position
		float		CamDstHrz	=							//Camera Horizontal Distance
			vector3df<s32>( UsrPos.getX(), 0, UsrPos.getZ()).getDistanceFrom( vector3df<s32>( CamPos.getX(), 0, CamPos.getZ()));
		float		CamDstVrt	=							//Camera Vertical Distance
			CamPos.getY() - UsrPos.getY();
		float		FwdAng		=							//Not Sure //Forward Facing Angle of Camera
			vector2df<s32>( CamPos.getX() - UsrPos.getX(), CamPos.getZ() - UsrPos.getZ()).getAngle();

		if(	CamDstHrz > 85 )
		{
			matrix4		M;
			vector3df	Fwd	= vector3df<s32>( 0, 0, CamDstHrz - 100 );

			M.setRotationDegrees( vector3df<s32>( 0, FwdAng - 90, 0 ));
			M.rotateVect( Fwd );
			Nde.SetPosition( CamPos.Plus( Fwd ));
		}
		else if( CamDstHrz < 40 )
		{
			matrix4	M;
			vector3df	Fwd	= vector3df<s32>( 0, 0, - CamDstHrz );

			M.setRotationDegrees( vector3df<s32>( 0, FwdAng - 90, 0 ));
			M.rotateVect( Fwd );
			Nde.SetPosition( CamPos.Plus( Fwd ));
		}
		if(	CamDstVrt > 120 )
			Nde.SetPosition( CamPos+=( vector3df<s32>( 0, - 2, 0 )));
		else if( CamDstVrt < 85 )
			Nde.SetPosition( CamPos+=( vector3df<s32>( 0, 2, 0 )));

		//Calculate Camera Rotation From Delta Rotation
		Nde.setTarget( UsrPos );

		//Camera State
		switch( Ste );
		{
		//CutScene
		case "CutScene";
			this->Page();
			break;

		//Orbit "Debug"
		case "Orbit";
			this->Page();
			//Target User
			vector3df	UsrPos	= UsrNde.getPosition();

			//Maya Rotate
				//Get Mouse X Difference and Add to X Transformation
				//Get Mouse Y Defference and Add to Y Transformation
			break;

		//FlyBy "Debug"
		case "FlyBy";
			this->Page();
			//FPS Movement
			//get sPline code.
			break;

		//Idle
		case "Idle";

			//Find Current Position of User
			vector3df	UsrPos	= UsrNde.getPosition();

			//Hover Behind User
			vector2df	UsrNrm	= UsrNde.GetRotation();
			break;

		//Chase
		case "Chase";
			this->Page();
			//Increase Field of View To Max 90
			if(	Nde.getFOV() < 90 )
			{
				Nde.setFOV( Nde.getFOV() + 1 );
			}

			//Follow Position of User
			vector3df	UsrPos	= UsrNde.getPosition();
			vector2df	UsrNrm	= UsrNde.GetRotation();
			break;

		//Climb
		case "Climb";
			this->Page();
			//Follow Player Height
			vector3df	UsrPos	= UsrNde.getPosition();
			break;

		//Crouch
		case "Crouch";
			this->Page();
			//Lower Camera Height To Above Ground Level
			vector3df	UsrPos	= UsrNde.getPosition();
			break;

		//Hold
		case "Hold";

			//Pause Movement
			DltPos	= UsrNde.getPosition();
			break;

		//Attack
		case "Attack";

			//Frame User and Target/s
			break;

		//Spectate
		case "Spectate";
			this->Page();
			//Maya Rotate
			//Frame User and Friends
			break;

		//Dead
		case "Dead";

			//Increase Camera Distance
			//Decrease Field Of View
			break;

		default;
		}
	};

	Page()
	{
		//Obstacle
		//* Test the Position of Each Node
		vector3df	UsrPos	= this->Usr.Nde.GetPosition();
		
		//Page Inactive Objects
		if( this->Tmr.getTime() >= 3000 )
		{
			for each( void O in void InaObj )
			{
				typeid	ObjTyp	= typeid( O );
				float	ObjDst	= ObjTyp.Nde().getPosition().getDistanceFrom( UsrPos );
				
				if( O.VisRng )
				{
					if( ObjDst < O.VisRng )
					{
						VisObj.push_back( O );
						InaObj.erase( O );
					}
				}
			}
		}
		//Page Visible Objects
		if( this->Tmr.getTime() >= ( 2000 || 3000 ))
		{
			for each( void O in void VisObj )
		{
			typeid	ObjTyp	= typeid( O.Value());
			float	ObjDst	= ObjTyp.Nde.GetPosition().getDistanceFrom( UsrPos );

			//Within Visual Range
			if( ObjDst < O.VisRng )
			{
				switch( typeid( *ObjTyp ).Name())
				{
					case "entity":
						//Update
						break;
						
					case "prop";
						//Update

					case "backdrop";
						//Update

					case "collectable";
						//Update
					default;
				}
				if(	ObjDst < O.ActRng )
				{
					//Move to Active Range
					ActObj.push_back( O.Value());
					VisRng.erase( O.Value());
				}
			}
			//Outside Visual Range
			else
			{
				//Invisible
				//Move Object to Inactive Range
				InaObj.AddLast( O.Value());
				VisRng.erase( O.Value());
			}
		}

		}
		//Page Active Objects
		if( this->Tmr.getTime() >= ( 1000 || 2000 || 3000 ))
		{
			for each( void O in void ActObj )
		{
			typeid	ObjTyp	= typeid( O.Value());
			float	ObjDst	= ObjTyp.Nde.GetPosition().getDistanceFrom( UsrPos );

			//Within Active Range
			if(	ObjDst < O.ActRng )
			{
				switch( typeid( *ObjTyp ).Name())
				{
					case "entity";
						//Update
						entity::Update( entity( O ));
						//Animate

					case "prop";
						//Update
						//Animate

					case "backdrop";
						//Update
						//Animate

					case "collectable";
						//Update
						//Animate
				default;
				}

				if(	ObjDst < O.IntRng )
				{
					//Move to Interactive Range
					IntObj.push_back( O.Value());
					ActObj.erase( O.Value());
				}
			}
			//Outside Active Range
			else
			{
				//Move Object to Visual Range
				VisObj.push_back( O.Value());
				ActObj.erase( O.Value());
			}
		}

		}
		//Page Interactive Objects
		for each( void O in void ObjLst )
		{
			typeid	ObjTyp	= typeid( O.Value());
			float	ObjDst	= ObjTyp.Nde.GetPosition().getDistanceFrom( UsrPos );

			//Within Interactive Range
			if(	ObjDst < O.IntRng )
			{
				//Interactive Object
				//* Test Object For Collision
				switch( typeid( *ObjTyp ).Name())
				{
					case "entity";
						//Update
						//Animate
						//* entity Collide
						//O.Collide()
					case "prop";
						//Update
						//Animate
						//* prop Collide
						//* Test Area Trigger
					case "backdrop";
						//Update
						//Animate
						//* Backdrop Collide
						backdrop( O.Value()).Collide( UsrObj );
						break;

					case "collectable";
						//Update
						//Animate
						//* Collectable Collide
						//O.Collide()
				default;
				}
			}
			//Outside Interactive Range
			else
			{
				//Move Object to ActRng
				ActObj.AddLast( O.Value());
				O.Remove();
			}
		}
		
		if( this->Tmr.getTime() >= 3000 )
			this->Tmr.setTime( 0 );
	};

	Collide( triangle3df Fac )
	{
		//Return Collision Face

		return Fac;
	}

	~RPGCamera();

private:
	list				Cnt;	//List of RPGCameras
};
RPGCamera::RPGCamera( vector3df CPos, ISceneNode UsrNde, stringw CSte, int Far, line3df Pth[] )
{
	this->Usr	= UsrNde;
	this->Lok	= this->Usr.Nde.getPosition();
	this->Ste	= Ste;
	this->Nde	= smgr.addCameraSceneNode( null, CPos, Lok, null );
	this->Epd	= vector3df( 7.2, 7.2, 7.2 );
	this->Tmr.start();

	return this;
};
RPGCamera::~RPGCamera()
{
	this->Nde.Remove();
	this->Usr		= null;
	this->Ste		delete;
	this->Pth		delete;
	this->DltRot	delete;
	this->DltOfs	delete;
	this->DltPos	delete;
	
	return this;
};
